package service

import (
	"bgs/conf"
	"bgs/db"
	"context"
	"fmt"
	// "github.com/pkg/errors"
	"go.uber.org/zap"
	"runtime"
	"strings"
	// "prod/pkg/env"
	// "prod/pkg/log"
	// "prod/pkg/request_key"
	// "prod/pkg/wechat"
)

const (
	stackDepth = 20
)

// FailOverServiceImp 故障转移服务实现
type FailOverServiceImp struct {
	dao  *db.PgDao
	slog *zap.SugaredLogger
	vars *conf.VarsSection
}

// NewFailOverServiceImp initialization
func NewFailOverServiceImp(
	pgdao *db.PgDao,
	slog *zap.SugaredLogger,
	vars *conf.VarsSection,
) *FailOverServiceImp {
	return &FailOverServiceImp{
		dao:  pgdao,
		slog: slog.With("module", "FailOverService"),
		vars: vars,
	}
}

// SafeAsyncExec go func 执行
func (s *FailOverServiceImp) SafeAsyncExec(ctx context.Context) {
	var errInfo string
	if r := recover(); r != nil {
		errInfo = s.getPanicTrace("async", r)
	}
	if errInfo != "" {
		s.slog.Infof("waiting failover=>%s", errInfo)
		// log.FromContext(ctx).Error(errInfo)
		// if envType != env.Local {
		// 	wechat.AsyncSendMarkDown(
		// 		ctx, wechat.FormatBugMessage(
		// 			ctx, envType, serviceName, request_key.GetRequestID(ctx),
		// 			"异步处理任务失败",
		// 			errInfo))
		// }
	}
}

func (s *FailOverServiceImp) getPanicTrace(serviceName string, r interface{}) string {
	buf := make([]byte, 64<<10)
	buf = buf[:runtime.Stack(buf, false)]
	stackLines := make([]string, 0)
	methodCache := ""
	// 格式化stackTrace，仅保留需要读取的部分进行拼接
	panicLineLocated := false
	for _, stackLine := range strings.Split(string(buf), "\n") {
		if !panicLineLocated {
			if !strings.Contains(stackLine, "/runtime/panic.go") {
				// 丢弃runtime/panic.go之前的信息
				continue
			}
			panicLineLocated = true
			// panic行同样丢弃
			continue
		}
		if strings.HasPrefix(stackLine, "\t") {
			if methodCache == "grpc.(*Server).interceptor.func1" {
				// grpc拦截器trace可以跳过
				continue
			}
			stackLines = append(stackLines, fmt.Sprintf("%s %s",
				strings.Split(stackLine[1:], " +0x")[0], methodCache))
			if len(stackLines) > stackDepth {
				break
			}
		} else if strings.Contains(stackLine, "/") {
			pieces := strings.Split(stackLine, "/")
			methodCache = strings.Split(pieces[len(pieces)-1], "(0x")[0]
			if methodCache == "go-nsq.(*Consumer).handlerLoop" {
				// nsq终点
				break
			} else if strings.HasPrefix(methodCache, "pb.") {
				// grpc终点
				break
			}
		} else {
			continue
		}
	}
	return fmt.Sprintf("%s: panic recovered: %s\n%s", serviceName, r, strings.Join(stackLines, "\n"))
}
